package com.jiangjiang.eshop.promotion.biz;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Sets;
import com.jiangjiang.eshop.membership.service.MembershipService;
import com.jiangjiang.eshop.order.dto.CouponDTO;
import com.jiangjiang.eshop.promotion.constant.CouponGiveOutType;
import com.jiangjiang.eshop.promotion.constant.CouponStatus;
import com.jiangjiang.eshop.promotion.convert.CouponConvert;
import com.jiangjiang.eshop.promotion.domain.CouponAchieveEntity;
import com.jiangjiang.eshop.promotion.domain.CouponEntity;
import com.jiangjiang.eshop.promotion.dto.CouponQueryPageDTO;
import com.jiangjiang.eshop.promotion.service.CouponAchieveService;
import com.jiangjiang.eshop.promotion.service.CouponService;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName CouponBiz
 * @Description TODO
 * @Author jhw
 * @Date 2021/8/22 17:16
 * @Version 1.0
 **/
@Component
public class CouponBiz {
    @Autowired
    private CouponService couponService;
    @Autowired
    private CouponConvert couponConvert;
    @Autowired
    private CouponAchieveService couponAchieveService;
    @Autowired
    private MembershipService membershipService;

    /**
     * 根据优惠券id集合查询一批优惠券数据
     *
     * @param id 优惠券id
     * @return 查询结果
     */
    public CouponDTO queryById(Long id) {
        List<CouponDTO> dtoList = this.queryByIds(Sets.newHashSet(id));
        if (CollectionUtils.isEmpty(dtoList)) {
            return null;
        }

        return dtoList.get(0);
    }


    /**
     * 根据优惠券id集合查询一批优惠券数据
     *
     * @param couponIdSet 优惠券id集合
     * @return 查询结果
     */
    public List<CouponDTO> queryByIds(Set<Long> couponIdSet) {
        return couponConvert.convertEntities2DTOList(couponService.queryByIds(couponIdSet));
    }

    /**
     * 分页查询优惠券数据
     *
     * @param dto 查询条件
     * @return 查询结果
     */
    public Page<CouponDTO> queryForPage(CouponQueryPageDTO dto) {
        Page<CouponEntity> page = new Page<>(dto.getPageNo(), dto.getPageSize(), true);
        LambdaQueryWrapper<CouponEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.like(Strings.isNotEmpty(dto.getName()), CouponEntity::getName, dto.getName())
                .eq(dto.getType() != null, CouponEntity::getType, dto.getType())
                .ge(Objects.nonNull(dto.getValidStartTime()), CouponEntity::getValidStartTime, dto.getValidStartTime())
                .le(Objects.nonNull(dto.getValidEndTime()), CouponEntity::getValidEndTime, dto.getValidEndTime())
                .eq(dto.getStatus() != null, CouponEntity::getStatus, dto.getStatus());
        return couponConvert.convertEntityPage2DTOPage(couponService.getBaseMapper().selectPage(page, wrapper));
    }

    /**
     * 保存优惠券
     *
     * @param dto 优惠券新增入参
     * @return 处理结果
     */
    public Boolean saveCoupon(CouponDTO dto) {
        CouponEntity couponEntity = couponConvert.convertDTO2Entity(dto);
        couponEntity.setStatus(CouponStatus.UNSTARTED);
        return couponService.save(couponEntity);
    }

    /**
     * 更新优惠券
     * @param dto 优惠券入参
     * @return 处理结果
     */
    public Boolean updateCoupon(CouponDTO dto) {
        if(dto.getReceivedCount() > 0L){
            return false;
        }
        return couponService.updateById(couponConvert.convertDTO2Entity(dto));
    }

    /**
     * 优惠券删除
     * @param id 优惠券id
     * @return 处理结果
     */
    public Boolean removeCoupon(Long id) {
        return couponService.removeById(id);
    }

    /**
     * 优惠券领取
     * @param couponId 优惠券 id
     * @param userAccountId 用户账户id
     * @return
     */
    public Boolean achieve(Long couponId, Long userAccountId) {
        // 获取优惠券数据
        CouponEntity coupon = couponService.getById(couponId);

        // 判断是否可以领取优惠券
        if(!canAchieve(coupon)){
            return false;
        }

        // 判断是否已经领取过了
        if(hasAchieved(couponId,userAccountId)){
            return false;
        }

        // 创建领取记录
        couponAchieveService.save(createCouponAchieve(couponId,userAccountId));
        // 更新优惠券领取数量
        updateCouponReceivedCount(coupon,1L);

        return true;
    }

    /**
     * 更新优惠券领取数量
     * @param coupon
     * @param updateReceivedCount
     */
    private void updateCouponReceivedCount(CouponEntity coupon, Long updateReceivedCount) {
        coupon.setReceivedCount(coupon.getReceivedCount() + updateReceivedCount);
        if(coupon.getReceivedCount() >= coupon.getGiveOutCount()){
            coupon.setStatus(CouponStatus.GIVEN_OUT);
        }
        couponService.updateById(coupon);
    }

    /**
     * 创建优惠券领取记录
     * @param couponId 优惠券id
     * @param userAccountId 用户账号id
     * @return
     */
    private CouponAchieveEntity createCouponAchieve(Long couponId, Long userAccountId) {
       return CouponAchieveEntity.builder()
                .couponId(couponId)
                .userAccountId(userAccountId)
                .isUsed(0)
                .usedTime(null)
                .build();
    }

    /**
     * 内否领取优惠券
     * @param coupon
     * @return
     */
    private boolean canAchieve(CouponEntity coupon) {
        Boolean isGivingOutStatus = CouponStatus.GIVING_OUT.equals(coupon.getStatus());
        Boolean isAchievableGiveOutType = CouponGiveOutType.ACHIEVABLE_AND_GIVE_OUT.equals(coupon.getGiveOutType())
                || CouponGiveOutType.ONLY_ACHIEVABLE.equals(coupon.getGiveOutType());
        return isGivingOutStatus && isAchievableGiveOutType;
    }

    /**
     * 是否已经领取过了
     * @param couponId
     * @param userAccountId
     * @return
     */
    private boolean hasAchieved(Long couponId, Long userAccountId) {
        return  couponAchieveService.checkAccountHasAchieved(couponId,userAccountId);
    }


    /**
     * 优惠券发放
     * @param couponId 优惠券id
     * @return
     */
    public Boolean giveOut(Long couponId) {
        CouponEntity coupon = couponService.getById(couponId);
        if(!canGiveOut(coupon)){
            return false;
        }
        // 为所有的用户发放优惠券
        giveOutForAllUserAccount(coupon);
        // 更新优惠券领取记录
        updateCouponReceivedCount(coupon,coupon.getGiveOutCount());
        return true;
    }

    /**
     * 向所有用户发放优惠券
     * @param coupon 优惠券
     */
    private void giveOutForAllUserAccount(CouponEntity coupon) {
        List<CouponAchieveEntity> entities = membershipService.listAllUserAccounts()
                .stream()
                .map(userAccountDTO ->
                        createCouponAchieve(coupon.getId(), userAccountDTO.getId())).collect(Collectors.toList()
                );
        couponAchieveService.saveBatch(entities);
    }

    /**
     * 能否发放
     * @param coupon 优惠券
     * @return 判断结果
     */
    private Boolean canGiveOut(CouponEntity coupon) {
        Boolean isGivingOutStatus = CouponStatus.GIVING_OUT.equals(coupon.getStatus());
        Boolean isGiveOutType = CouponGiveOutType.ACHIEVABLE_AND_GIVE_OUT.equals(coupon.getGiveOutType())
                || CouponGiveOutType.ONLY_GIVE_OUT.equals(coupon.getGiveOutType());
        return isGivingOutStatus && isGiveOutType;
    }
}
